package com.example.mykotlin.base.config

import cn.dev33.satoken.interceptor.SaInterceptor
import com.example.mykotlin.base.config.converter.StringToDateConverter
import com.example.mykotlin.base.config.converter.StringToLocalDateConverter
import com.example.mykotlin.base.config.converter.StringToLocalDateTimeConverter
import com.example.mykotlin.base.interceptor.DeviceInterceptor
import com.example.mykotlin.base.interceptor.RequestInfoInterceptor
import com.example.mykotlin.base.util.Constant
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer
import java.io.IOException
import java.time.LocalDate
import java.time.LocalDateTime
import org.apache.commons.lang3.StringUtils
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Configuration
import org.springframework.format.FormatterRegistry
import org.springframework.http.converter.HttpMessageConverter
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
import org.springframework.web.servlet.config.annotation.InterceptorRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer


@Configuration
class MyWebMvcConfig(
    private val deviceInterceptor: DeviceInterceptor,
    private val requestInfoInterceptor: RequestInfoInterceptor,
) : WebMvcConfigurer {

    @Value("\${sa-token.ignore-url:}")
    private var ignoreUrl: String = ""

    override fun addFormatters(registry: FormatterRegistry) {
        registry.addConverter(StringToDateConverter())
        registry.addConverter(StringToLocalDateConverter())
        registry.addConverter(StringToLocalDateTimeConverter())
    }

    override fun addInterceptors(registry: InterceptorRegistry) {
        val sa = registry.addInterceptor(SaInterceptor()).addPathPatterns("/**")
        val device = registry.addInterceptor(deviceInterceptor).addPathPatterns("/**")
        val ignoreUrlList = ignoreUrl.split(",").filter { StringUtils.isNotBlank(it) }.map { it.trim() }.toMutableList()
        if (ignoreUrlList.isNotEmpty()) {
            sa.excludePathPatterns(ignoreUrlList)
            device.excludePathPatterns(ignoreUrlList)
        }
        registry.addInterceptor(requestInfoInterceptor).addPathPatterns("/**")
    }


    override fun configureMessageConverters(converters: MutableList<HttpMessageConverter<*>>) {
        val jackson2HttpMessageConverter = MappingJackson2HttpMessageConverter()
        val objectMapper = ObjectMapper()

        val simpleModule = SimpleModule().addSerializer(Long::class.java, ToStringSerializer.instance)
            .addSerializer(java.lang.Long.TYPE, ToStringSerializer.instance)
            .addSerializer(java.lang.Long::class.java, ToStringSerializer.instance)
            .addSerializer(LocalDateTime::class.java, LocalDateTimeSerializer(Constant.DTF))
            .addDeserializer(LocalDateTime::class.java, LocalDateTimeDeserializer(Constant.DTF))
            .addSerializer(LocalDate::class.java, LocalDateSerializer(Constant.DF))
            .addDeserializer(LocalDate::class.java, LocalDateDeserializer(Constant.DF))
            .addDeserializer(String::class.java, object : StdScalarDeserializer<String?>(String::class.java) {
                @Throws(IOException::class)
                override fun deserialize(jsonParser: JsonParser, ctx: DeserializationContext?): String =
                    jsonParser.valueAsString.trim()
            })
        objectMapper.registerModule(simpleModule)
        jackson2HttpMessageConverter.objectMapper = objectMapper
        converters.add(jackson2HttpMessageConverter)
    }

}